﻿#region License

// Copyright (c) 2008, BXO Solutions AB
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright notice, 
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright 
//       notice, this list of conditions and the following disclaimer in the 
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the BXO Solutions AB nor the names of its 
//       contributors may be used to endorse or promote products derived from 
//       this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#endregion

using System;
using NUnit.Framework;
using NUnit.Framework.Extensions;
using NUnit.Framework.SyntaxHelpers;

namespace Bxo.TestingPortal.Entities.Tests {
    [TestFixture]
    public class ScenarioFixture {
        #region Setup/Teardown

        [SetUp]
        public void SetUp() {
            this.testee = new Scenario(new ScenarioVersion("some_summary", "some_instruction"));
        }

        #endregion

        private Scenario testee;

        private static Project CreateTestProject() {
            return CreateTestProject("some_project");
        }

        private static Project CreateTestProject(string name) {
            return new Project(name);
        }

        [Test]
        [ExpectedException(typeof (ArgumentException))]
        public void CategoryAddingFailsWhenCategoryHasAnotherProject() {
            Project project1 = CreateTestProject("project1");
            Project project2 = CreateTestProject("project2");

            var category = new Category("category");

            project1.Scenarios.Add(this.testee);
            project2.Categories.Add(category);

            this.testee.Categories.Add(category);
        }

        [Test]
        [ExpectedException(typeof (ArgumentException))]
        public void CategoryAddingFailsWhenCategoryHasNoProject() {
            CreateTestProject().Scenarios.Add(this.testee);

            var category = new Category("category");
            // Do not add the category to the project.

            this.testee.Categories.Add(category);
        }

        [Test]
        [ExpectedException(typeof (InvalidOperationException))]
        public void CategoryAddingFailsWhenCategoryIsAlreadyAdded() {
            Project project = CreateTestProject();
            project.Scenarios.Add(this.testee);

            var category = new Category("a_category");
            project.Categories.Add(category);

            this.testee.Categories.Add(category);
            this.testee.Categories.Add(category);
        }

        [Test]
        public void CategoryAddingSuccess() {
            Project project = CreateTestProject();
            project.Scenarios.Add(this.testee);

            var category = new Category("category");
            project.Categories.Add(category);

            this.testee.Categories.Add(category);

            Assert.That(this.testee.Categories, Is.EquivalentTo(new[] {category}));
            Assert.That(category.Scenarios, Is.EquivalentTo(new[] {this.testee}));
        }

        [Test]
        public void CategoryClearingSuccess() {
            Project project = CreateTestProject();

            var category = new Category("category");
            project.Categories.Add(category);

            project.Scenarios.Add(this.testee);
            this.testee.Categories.Add(category);
            this.testee.Categories.Clear();

            Assert.That(this.testee.Categories, Is.Empty);
            Assert.That(category.Scenarios, Is.Empty);
        }

        [Test]
        public void CategoryRemovalDoesNothingWhenCategoryNotAdded() {
            this.testee.Categories.Remove(new Category("category"));
        }

        [Test]
        public void CategoryRemovalSuccess() {
            Project project = CreateTestProject();

            var category = new Category("category");
            project.Categories.Add(category);

            project.Scenarios.Add(this.testee);
            this.testee.Categories.Add(category);
            this.testee.Categories.Remove(category);

            Assert.That(this.testee.Categories, Is.Empty);
            Assert.That(category.Scenarios, Is.Empty);
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void CtorFailsOnNullVersion() {
            new Scenario(null);
        }

        [Test]
        [ExpectedException(typeof (ArgumentException))]
        public void CtorFailsOnVersionWhichIsAlreadyUsed() {
            var version = new ScenarioVersion("summary", string.Empty);

            new Scenario(version);
            new Scenario(version);
        }

        [Test]
        public void CtorSetsProperties() {
            var version = new ScenarioVersion("some_summary", "some_instruction");
            var testee = new Scenario(version);
            Assert.That(testee.Categories, Is.Not.Null, "Problem with list of categories.");
            Assert.That(testee.Categories, Is.Empty, "Problem with list of categories.");
            Assert.That(testee.IsActive, Is.True, "Problem with activity indication.");
            Assert.That(testee.Project, Is.Null, "Problem with project.");
            Assert.That(testee.Versions, Is.Not.Null, "List of versions is null.");
            Assert.That(testee.Versions, Has.Count(1), "List of versions must contain only the initial version.");
            Assert.That(testee.Versions.IsReadOnly, Is.True, "List of version must be readonly.");
            Assert.That(testee.CurrentVersion, Is.SameAs(version), "Version is not set properly.");
            Assert.That(testee.CurrentVersion.Scenario, Is.SameAs(testee), "Version has no assigned scenario.");
        }

        [Test]
        public void IsActiveSetterWorks() {
            this.testee.IsActive = false;
            Assert.That(this.testee.IsActive, Is.False);

            this.testee.IsActive = true;
            Assert.That(this.testee.IsActive, Is.True);
        }

        [RowTest]
        [Row("summary1")]
        [Row("summary2")]
        public void ToStringReturnsCurrentSummary(string summary) {
            var testee = new Scenario(new ScenarioVersion(summary, "some_instruction"));
            Assert.That(testee.ToString(), Is.SameAs(summary));
        }

        [Test]
        [ExpectedException(typeof (ArgumentException))]
        public void UpdateFailsIfUpdatingToSameVersionAsCurrent() {
            var version = new ScenarioVersion("a_summary", "an_instruction");
            var testee = new Scenario(version);

            testee.Update(version);
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void UpdateFailsOnNullVersion() {
            var testee = new Scenario(new ScenarioVersion("a_summary", "an_instruction"));

            testee.Update(null);
        }

        [Test]
        [ExpectedException(typeof (ArgumentException))]
        public void UpdateFailsWhenVersionIsAlreadyUsedBySomeScenario() {
            var shared = new ScenarioVersion("a_summary", "an_instruction");
            new Scenario(shared);

            var testee = new Scenario(new ScenarioVersion("another_summary", string.Empty));
            testee.Update(shared);
        }

        [Test]
        public void UpdatingManagesHistoryOfVersions() {
            var first = new ScenarioVersion("a_summary", "an_instruction");
            var testee = new Scenario(first);

            var second = new ScenarioVersion("new_summary", "new_instruction");

            testee.Update(second);

            Assert.That(testee.Versions, Has.Count(2), "List of versions has invalid count.");
            Assert.That(testee.Versions[0], Is.SameAs(first), "First version has been overwritten.");
            Assert.That(testee.Versions[1], Is.SameAs(second), "Second version has not been set correctly.");
        }

        [Test]
        public void UpdatingSetsNewCurrentVersionAndBindsItToScenario() {
            var first = new ScenarioVersion("a_summary", "an_instruction");
            var testee = new Scenario(first);

            var second = new ScenarioVersion("new_summary", "new_instruction");

            testee.Update(second);

            Assert.That(testee.CurrentVersion, Is.SameAs(second), "Version has not been updated.");
            Assert.That(testee.CurrentVersion.Scenario, Is.SameAs(testee), "Version has not been bound to the scenario.");
        }
    }
}